<template>
  <div class="component-upload-image">
    <el-upload :action="uploadUrl"
               ref="uploadCom"
               :list-type="listType"
               :file-list="fileList"
               :data="uploadData"
               :headers="uploadHeaders"
               v-bind="$attrs"
               :disabled="disabled"
               :before-upload="handleBeforeUpload"
               :on-preview="handlePreview"
               :on-remove="removeFile"
               :on-exceed="exceedImage"
               :on-success="handleUploadSuccess"
               :on-error="handleUploadError">
      <i v-if="!$slots.trigger && uploadTriggerShow && fileType == 1"
         class="el-icon-plus" />
      <div v-if="!$slots.trigger && uploadTriggerShow && (fileType == 4 || fileType == 3)">
        <el-button icon="el-icon-upload2">选择上传</el-button>
      </div>
      <div slot="trigger"
           v-if="$slots.trigger && uploadTriggerShow">
        <slot name="trigger"></slot>
      </div>
      <div slot="tip">
        <slot name="tip"></slot>
      </div>
      <div class="custom-file-list"
           slot-scope="{file}"
           slot="file">
        <div class="upload-image-con"
             v-if="fileType == 1"
             @click="handlePreview(file)">
          <div v-if="!disabled"
               class="upload-image-delete"
               @click.stop="removeFile(file)"><i class="el-icon-close"></i></div>
          <el-image class="file-img"
                    :src="file.url"
                    fit="cover"></el-image>
        </div>
        <div class="upload-video-con"
             v-if="fileType == 2">
          <video class="upload-video"
                 :src="file.url"></video>
          <div class="video-play-con">
            <i class="iconfont icon-icon-bofang"></i>
          </div>
          <span class="el-upload-list__item-actions">
            <span class="el-upload-list__item-preview"
                  @click="handlePreview(file)">
              <i class="el-icon-zoom-in"></i>
            </span>
            <span v-if="!disabled"
                  class="el-upload-list__item-delete"
                  @click="removeFile(file)">
              <i class="el-icon-delete"></i>
            </span>
          </span>
        </div>
        <div class="upload-file-con"
             v-if="fileType == 3"
             @click="handlePreview(file)">
          <div class="file-text">
            <i class="iconfont icon-wenjian1 file-icon"></i>
            <span class="file-text-name"> {{file.name}} </span>
          </div>
          <div>
            <i class="el-icon-delete option-icon"
               @click.stop="removeFile(file)"
               v-if="!disabled"></i>
          </div>
        </div>
        <div class="upload-audio-con"
             :class="{'audio-play': audioStatus=='pause'}"
             v-if="fileType == 4">
          <div class="preview-con"
               @click="handlePreview(file)"
               :class="{'no-event': file.status != 'success'}">
            <custom-audio :fileurl="file.url"
                          :fileTime="file.fileTime"
                          controls
                          @on-duration="audioDuration"
                          @updateCurrentTime="updateCurrentTime"
                          @updateStatus="updateStatus"></custom-audio>
            <div class="preview-text">播放</div>
          </div>
          <div class="file-info-con">
            <div class="file-name"
                 :title="file.name">
              <span class="file-name-prefix">{{ substringFileName(file, 'prefix') }}.</span>
              <span class="file-name-suffix">{{ substringFileName(file) }}</span>
            </div>
            <div class="extra-info"
                 v-if="file.status == 'success'">
              <span>{{file.fileSize ? fileSizeFormat(file.fileSize) : ''}}</span>
              <div class="file-time-info">
                <span>{{ file.currentTime ? `${file.currentTime}/` : '00:00/' }}</span>
                <span>{{ transTime(parseFloat(file.fileTime)) }}</span>
              </div>
            </div>
            <div class="extra-info"
                 v-if="file.status == 'uploading'">
              <el-progress :percentage="file.percentage"
                           :stroke-width="4" />
            </div>
          </div>
          <div class="option-con">
            <!-- 删除 -->
            <i class="iconfont icon-shanchu option-icon"
               v-if="!disabled && file.status == 'success'"
               @click.stop="removeFile(file)"></i>
            <!-- 关闭 -->
            <i class="iconfont icon-guanbi1 option-icon"
               @click.stop="cancelUpload(file)"
               v-if="file.status == 'uploading'"></i>
          </div>
        </div>
      </div>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible"
               title="预览"
               width="800"
               append-to-body>
      <div style="width: 100%; display: flex; align-items: center">
        <video style="max-width: 100%; max-height: 80vh; margin: auto"
               v-if="fileType === '2'"
               :src="previewUrl"
               controls></video>
      </div>
    </el-dialog>
    <el-image style="position: absolute; display: none; left: -10000px"
              ref="imagePreview"
              :preview-src-list="previewImageList"
              v-if="fileType === '1'"
              :src="previewUrl"
              fit="contain"></el-image>
  </div>
</template>

<script>
import { getToken } from '@/utils/auth'
import { downloadByUrl } from '@/utils/ruoyi'
import { downloadURL } from '@/utils/downloadFile'
import { delFile } from '@/api/oss/oss'
import CustomAudio from '@/components/CustomAudio/new.vue'
export default {
  components: {
    CustomAudio
  },
  data() {
    return {
      dialogVisible: false, // 预览弹窗
      previewUrl: '', // 预览地址
      uploadUrl: process.env.VUE_APP_UPLOAD_BASE_API + '/common/upload', // 上传的图片服务器地址
      customHeaders: {
        Authorization: 'Bearer ' + getToken(),
      },
      loading: null, // loading
      uploadTriggerShow: !this.disabled, // 是否显示上传区域
      audioStatus: '' // 语音状态 
    }
  },
  computed: {
    previewImageList() {
      return this.fileList.map((item) => item.url)
    },
    fileList() {
      const list = this.value
        .filter((item) => item.delFlag !== '1' && item.url)
        .map((j) => {
          j.status = 'success';
          return j;
        });
      return list;
    },
    uploadData() {
      return { ...this.data, pathPrefix: this.pathPrefix, fileType: this.fileType, }
    },
    uploadHeaders() {
      return { ...this.headers, ...this.customHeaders }
    },
  },
  props: {
    value: {
      type: Array,
      default: () => [],
    }, // 文件数据 [{url: 'https://ficot-erp-oss.oss-cn-shanghai.aliyuncs.com/servicePackage/servicePackagePicture/null/8936677042100.jpg',delFlag: '0'}]。 // delFlag：0 正常；1 删除；2 新增
    listType: {
      type: String,
      default: 'picture-card',
    }, // 文件列表的类型
    fileType: {
      type: String,
      default: '1',
    }, // 文件类型  1 图片。2 视频。3 文件。 4 音频。
    fileTypeRegx: {
    }, // 文件类型正则
    pathPrefix: {
      type: String,
      default: 'default',
    }, // 上传接口的前缀
    data: {
      type: Object,
      default: () => ({}),
    }, // 上传时附带的额外参数
    headers: {
      type: Object,
      default: () => ({}),
    }, // 设置上传的请求头部
    fileSize: {
      type: Number,
      default: 1024,
    }, // 设置文件大小--kb
    uploadLimit: {
      type: Function,
    }, // 上传限制函数--须为promise
    disabled: {
      type: Boolean,
      default: false,
    }, // 上传限制函数--须为promise
  },
  watch: {
    uploadTriggerShow: {
      handler(val) {
        this.uploadTriggerIsShow(val)
      },
      immediate: true,
      deep: true,
    },
    fileList: {
      handler(val) {
        if (!this.disabled && (!this.$attrs.limit || (this.$attrs.limit && val && val.length < this.$attrs.limit))) {
          this.uploadTriggerShow = true;
        } else {
          this.uploadTriggerShow = false;
        }
      },
      immediate: true,
      deep: true,
    },
  },
  methods: {
    /** 是否显示上传按钮 */
    uploadTriggerIsShow(show) {
      this.$nextTick(() => {
        const triggerDom = this.$refs.uploadCom.$el.getElementsByClassName(
          'el-upload--picture-card'
        )
        if (triggerDom.length) {
          triggerDom[0].style.display = show ? 'inline-block' : 'none'
        }
      })
    },
    /** 预览 */
    handlePreview(file) {

      if (this.fileType == 3) {
        window.location.href = file.url
        return
      }
      if (this.fileType == 4) {

        // downloadByUrl({ path: file.url, fileName: file.name || '语音' })
        // window.location.href = file.url
        return;
      }
      this.previewUrl = file.url
      if (this.fileType == 1) {
        this.$refs.imagePreview.clickHandler();
        return;
      }
      this.dialogVisible = true
    },
    /** 删除的回调 */
    removeFile(file) {
      if (file.status !== 'ready') {
        let fileList = [...this.value]
        const delIndex = fileList.findIndex((item) => item.url === file.url)
        if (file.delFlag === '2') {
          this.delFileRequest([file.url])
          fileList.splice(delIndex, 1)
        } else {
          fileList[delIndex].delFlag = '1'
        }
        this.$emit('input', fileList)
      }
    },
    /** 上传之前的回调 */
    handleBeforeUpload(file) {
      if (this.fileTypeRegx) {
        if (!this.fileTypeRegx.test(file.name)) {
          this.msgError("请上传符合要求的文件！");
          return false;
        }
      }
      if (this.fileType == 1) {
        if (!/\.(gif|jpg|jpeg|png|GIF|JPG|PNG)$/.test(file.name)) {
          this.msgError("图片类型必须是.gif,jpeg,jpg,png中的一种");
          return false;
        }
      }
      if (this.fileType == 2) {
        if (!/\.(avi|mp4|swf|flv|mpeg)$/.test(file.name)) {
          this.msgError("视频类型必须是.avi,mp4,swf,flv,mpeg中的一种");
          return false;
        }
      }
      if (this.fileType == 3) {
        if (!/\.(doc|docx|ppt|pptx|pdf|xlsx|xls)$/.test(file.name)) {
          this.msgError("文件类型必须是.doc,docx,ppt,pptx,pdf,xlsx,xls中的一种");
          return false;
        }
      }
      const isMoreThan = file.size / 1024 < this.fileSize
      if (!isMoreThan) {
        this.msgError(`${this.fileType == 1 ? '图片' : this.fileType == 2 ? '视频' : '文件'}大小不能超过${parseInt(this.fileSize / 1024)}M ！`)
        return false
      }
      if (this.uploadLimit) {
        return this.uploadLimit(file)
      }
      this.loading = this.$loading({
        lock: true,
        text: '上传中',
        background: 'rgba(0, 0, 0, 0.7)',
      })
    },
    /** 文件超出个数限制时的钩子 */
    exceedImage(file, list) {
      if (this.$attrs.limit) {
        this.$message.warning(`最多上传${this.$attrs.limit}张图片！`)
      }
    },
    /** 文件上传成功时的钩子 */
    handleUploadSuccess(res, file, fileLists) {
      if (res.code === 200) {
        let fileList = fileLists.reduce((acc, cur) => {
          if (cur.response) {
            acc.push({
              fileType: this.fileType,
              delFlag: '2',
              uid: cur.uid,
              ...cur.response.data,
            })
          } else {
            acc.push(cur)
          }
          return acc
        }, [])
        const delFileList = this.value.filter((item) => item.delFlag === '1')
        fileList = [...fileList, ...delFileList]
        this.$emit('input', fileList)
      } else {
        this.msgError(res.msg)
        this.$emit('input', [...this.value])
      }
      this.loading && this.loading.close()
    },
    /** 文件上传失败时的钩子 */
    handleUploadError() {
      this.$message({
        type: 'error',
        message: '上传失败',
      })
      this.loading.close()
    },
    /** 删除无用的图片 */
    deleteFiles() {
      const delFileList = this.value
        .filter((item) => item.delFlag === '2')
        .reduce((acc, cur) => {
          acc.push(cur.url)
          return acc
        }, [])
      if (delFileList.length) {
        this.delFileRequest(delFileList)
      }
    },
    /** 删除接口 */
    delFileRequest(urls) {
      // let formData = new FormData()
      // formData.append('urls', urls)
      delFile(urls)
    },
    /** 清空已上传的文件列表 */
    clearFiles() {
      this.$refs.uploadCom.clearFiles()
    },
    /** 取消上传请求 */
    abort(file) {
      this.$refs.uploadCom.abort(...arguments)
    },
    /** 取消上传请求 */
    submit() {
      this.$refs.uploadCom.submit()
    },
    /** 获取语音的时长 */
    audioDuration(file) {
      let fileList = [...this.value]
      let findIndex = fileList.findIndex(item => item.url === file.url);
      // fileList[findIndex]['fileTime'] = file.duration;
      // this.$emit('update:value', fileList)
      // console.log('获取语音的时长', file, fileList);
    },
    // 获取语音的播放时间
    updateCurrentTime(file) {
      let fileList = [...this.value]
      let findIndex = fileList.findIndex((item) => item.url === file.url);
      fileList[findIndex]['currentTime'] = file.currentTime;
      this.value.splice(findIndex, 1, fileList[findIndex])
    },
    // 更新语音播放状态
    updateStatus(audioStatus) {
      this.audioStatus = audioStatus
    },
    // 文件大小显示转换
    fileSizeFormat(fileSize) {
      let size = '';
      const file_kb = fileSize / 1024;
      const file_mb = fileSize / 1024 / 1024;
      if (file_kb < 1024) {
        size = parseFloat(file_kb.toFixed(2))
        return `${size}K`
      } else {
        size = parseFloat(file_mb.toFixed(2))
        return `${size}M`
      }
    },
    /**
 * 音频播放时间换算
 * @param {number} value - 音频当前播放时间，单位秒
 */
    transTime(time) {
      let duration = parseInt(time)
      let minute = Math.floor(duration / 60)
      let sec = (duration % 60) + ''
      let isM0 = ':'
      if (minute === 0) {
        minute = '00'
      } else if (minute < 10) {
        minute = '0' + minute
      }
      if (sec.length === 1) {
        sec = '0' + sec
      }
      return minute + isM0 + sec
    },
    // 取消上传切清除当前文件
    cancelUpload(file) {
      abort(file);
      this.$emit('update:value', [...this.value]);
    },
    // 根据文件名截取.前后的内容, 默认返回后缀名
    substringFileName(file, type = 'suffix') {
      if (file.name) {
        const index = str.lastIndexOf('.');
        if (type == 'suffix') {
          return str.substring(index);
        } else {
          return str.substring(0, index);
        }
      } else {
        if (type == 'suffix') {
          return file.fileFormat;
        } else {
          return '音频';
        }
      }
    }
  },
}
</script>

<style scoped lang="scss">
.component-upload-image {
  color: #333333;
  ::v-deep .el-upload-list__item-status-label {
    display: none;
  }
  .custom-file-list {
    height: 100%;
    width: 100%;
    // background-color: #ffffff;
    .no-event {
      pointer-events: none;
    }
    .file-info-con {
      width: calc(100% - 112px);
      .file-name {
        display: flex;
        word-break: break-all;
        .file-name-prefix {
          overflow: hidden;
          white-space: nowrap;
          text-overflow: ellipsis;
        }
        .file-name-suffix {
          word-break: normal;
        }
      }
    }
    .preview-con,
    .option-con {
      flex-shrink: 0;
    }
  }
  .upload-image-con {
    height: 100%;
    width: 100%;
    cursor: pointer;
    position: relative;
    .file-img {
      height: 100%;
      width: 100%;
    }
    .upload-image-delete {
      width: 24px;
      height: 24px;
      padding-left: 4px;
      line-height: 24px;
      text-align: center;
      background: #f34b3a;
      border-radius: 0px 4px 0px 100px;
      position: absolute;
      top: 0;
      right: 0;
      z-index: 1;
      .el-icon-close {
        display: block;
        font-size: 12px;
        color: #ffffff;
      }
    }
  }
  .upload-video-con {
    position: relative;
    width: 88px;
    height: 88px;
    .video-play-con {
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      position: absolute;
      top: 0;
      background: rgba(0, 0, 0, 0.5);
      font-size: 30px;
      color: #fafafa;
    }
    .upload-video {
      width: 100%;
      height: 100%;
    }
  }
  ::v-deep .preview-file-con {
    max-height: 80vh;
  }
  // .upload-audio-con {
  //   .audio-file-text {
  //     color: #333333;
  //     display: flex;
  //     justify-content: space-between;
  //     margin-bottom: 4px;
  //   }
  //   .audio-icon {
  //     padding: 0 10px;
  //     color: var(--theme);
  //   }
  //   .option-icon {
  //     margin-right: 14px;
  //     color: #999999;
  //     cursor: pointer;
  //   }
  //   .option-icon:hover {
  //     color: var(--theme);
  //   }
  // }

  .upload-audio-con {
    display: flex;
    align-items: center;
    height: 56px;
    background: #ffffff;
    border-radius: 4px;
    border: 1px solid #e8eaeb;
    --file-preview-text-show: block;
    --file-preview-icon-color: #9b9d9e;
    &:hover,
    &.audio-play {
      border: 1px solid var(--el-color-primary);
      --file-preview-text-show: block;
      --file-preview-icon-color: var(--el-color-primary);
    }
    .preview-con {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      width: 48px;
      height: 48px;
      margin-left: 4px;
      border-radius: 2px;
      background: #f7f9fa;
      text-align: center;
      cursor: pointer;
      color: var(--file-preview-icon-color);
      &.no-event {
        --file-preview-text-show: none;
        --file-preview-icon-color: #9b9d9e;
      }
      .preview-text {
        display: var(--file-preview-text-show);
        margin-top: 3px;
        font-size: 12px;
        line-height: 18px;
      }
      .option-icon {
        color: var(--file-preview-icon-color);
      }
    }
    .file-info-con {
      flex: 1;
      display: flex;
      flex-direction: column;
      padding: 8px;
      font-size: 12px;
      color: #646566;
      line-height: 25px;
      .extra-info {
        margin-top: 4px;
        display: flex;
        justify-content: space-between;
        .file-time-info {
          font-size: 12px;
        }
      }
    }
    .option-con {
      margin: 0 12px 0 24px;
    }
    .option-icon {
      font-size: 14px;
      color: #646566;
      cursor: pointer;
    }
  }
  .upload-audio-con:hover {
    background-color: #ffffff;
  }
  .upload-file-con {
    display: flex;
    align-items: center;
    .file-text {
      flex: 1;
      background: #f2f5f4;
      border-radius: 4px;
      // padding: 10px 14px;
      padding-right: 10px;
      font-size: 12px;
      color: #646566;
      line-height: 18px;
      // margin-right: 8px;
      display: flex;
      align-items: center;
      background: #ffffff;
      border-radius: 4px;
      border: 1px solid #e8eaeb;
      cursor: pointer;
      &:hover {
        color: $theme-color;
      }
      .file-icon {
        width: 48px;
        height: 48px;
        font-size: 20px;
        background: #f7f9fa;
        color: #9b9d9e;
        border-radius: 2px;
        display: flex;
        align-items: center;
        justify-content: center;
        margin: 4px 8px 4px 4px;
      }
      &-name {
        flex: 1;
        color: #646566;
      }
    }
    .file-icon {
      color: var(--theme);
      margin-right: 8px;
    }
    .option-icon {
      color: #999999;
      cursor: pointer;
    }
    .option-icon:hover {
      color: var(--theme);
    }
  }
  .upload-file-con:hover {
    background-color: #ffffff;
  }
}
</style>
